#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
MCP Calculator Server - Logging and Monitoring Utilities

日志和监控工具模块
"""

import logging
import logging.handlers
import time
import json
import threading
from typing import Dict, Any, Optional, List
from datetime import datetime, timedelta
from collections import defaultdict, deque
from functools import wraps
from dataclasses import dataclass, asdict
from pathlib import Path

@dataclass
class MetricData:
    """指标数据"""
    name: str
    value: float
    timestamp: datetime
    tags: Dict[str, str] = None
    
    def __post_init__(self):
        if self.tags is None:
            self.tags = {}

@dataclass
class OperationLog:
    """操作日志"""
    operation: str
    input_data: Dict[str, Any]
    output_data: Dict[str, Any]
    duration: float
    timestamp: datetime
    success: bool
    error: Optional[str] = None

class MetricsCollector:
    """指标收集器"""
    
    def __init__(self, max_history: int = 10000):
        self.max_history = max_history
        self.metrics = defaultdict(lambda: deque(maxlen=max_history))
        self.counters = defaultdict(int)
        self.gauges = defaultdict(float)
        self.histograms = defaultdict(list)
        self.operation_logs = deque(maxlen=max_history)
        self._lock = threading.Lock()
    
    def record_metric(self, name: str, value: float, tags: Dict[str, str] = None):
        """记录指标"""
        with self._lock:
            metric = MetricData(name, value, datetime.now(), tags or {})
            self.metrics[name].append(metric)
    
    def increment_counter(self, name: str, value: int = 1, tags: Dict[str, str] = None):
        """增加计数器"""
        with self._lock:
            key = f"{name}:{json.dumps(tags or {}, sort_keys=True)}"
            self.counters[key] += value
            self.record_metric(f"{name}_total", self.counters[key], tags)
    
    def set_gauge(self, name: str, value: float, tags: Dict[str, str] = None):
        """设置仪表盘值"""
        with self._lock:
            key = f"{name}:{json.dumps(tags or {}, sort_keys=True)}"
            self.gauges[key] = value
            self.record_metric(name, value, tags)
    
    def record_histogram(self, name: str, value: float, tags: Dict[str, str] = None):
        """记录直方图数据"""
        with self._lock:
            key = f"{name}:{json.dumps(tags or {}, sort_keys=True)}"
            self.histograms[key].append(value)
            
            # 保持最近的1000个值
            if len(self.histograms[key]) > 1000:
                self.histograms[key] = self.histograms[key][-1000:]
            
            self.record_metric(name, value, tags)
    
    def log_operation(self, operation: str, input_data: Dict[str, Any], 
                     output_data: Dict[str, Any], duration: float, 
                     success: bool, error: Optional[str] = None):
        """记录操作日志"""
        with self._lock:
            log_entry = OperationLog(
                operation=operation,
                input_data=input_data,
                output_data=output_data,
                duration=duration,
                timestamp=datetime.now(),
                success=success,
                error=error
            )
            self.operation_logs.append(log_entry)
            
            # 记录相关指标
            self.increment_counter('operations_total', tags={'operation': operation, 'success': str(success)})
            self.record_histogram('operation_duration', duration, tags={'operation': operation})
    
    def get_metrics_summary(self, time_window: Optional[timedelta] = None) -> Dict[str, Any]:
        """获取指标摘要"""
        with self._lock:
            now = datetime.now()
            cutoff_time = now - (time_window or timedelta(hours=1))
            
            summary = {
                'timestamp': now.isoformat(),
                'time_window': str(time_window) if time_window else 'all_time',
                'counters': dict(self.counters),
                'gauges': dict(self.gauges),
                'metrics': {},
                'operations': {
                    'total': len(self.operation_logs),
                    'success_rate': 0,
                    'avg_duration': 0,
                    'recent_errors': []
                }
            }
            
            # 计算指标统计
            for name, metric_list in self.metrics.items():
                recent_metrics = [m for m in metric_list if m.timestamp >= cutoff_time]
                if recent_metrics:
                    values = [m.value for m in recent_metrics]
                    summary['metrics'][name] = {
                        'count': len(values),
                        'min': min(values),
                        'max': max(values),
                        'avg': sum(values) / len(values),
                        'latest': values[-1]
                    }
            
            # 计算操作统计
            recent_ops = [op for op in self.operation_logs if op.timestamp >= cutoff_time]
            if recent_ops:
                success_count = sum(1 for op in recent_ops if op.success)
                summary['operations']['success_rate'] = success_count / len(recent_ops)
                summary['operations']['avg_duration'] = sum(op.duration for op in recent_ops) / len(recent_ops)
                summary['operations']['recent_errors'] = [
                    {'operation': op.operation, 'error': op.error, 'timestamp': op.timestamp.isoformat()}
                    for op in recent_ops[-10:] if not op.success
                ]
            
            return summary
    
    def get_operation_history(self, operation: Optional[str] = None, limit: int = 100) -> List[Dict[str, Any]]:
        """获取操作历史"""
        with self._lock:
            ops = list(self.operation_logs)
            if operation:
                ops = [op for op in ops if op.operation == operation]
            
            return [asdict(op) for op in ops[-limit:]]
    
    def clear_metrics(self):
        """清除所有指标"""
        with self._lock:
            self.metrics.clear()
            self.counters.clear()
            self.gauges.clear()
            self.histograms.clear()
            self.operation_logs.clear()

class EnhancedLogger:
    """增强的日志记录器"""
    
    def __init__(self, name: str, config: Dict[str, Any]):
        self.name = name
        self.config = config
        self.logger = logging.getLogger(name)
        self.metrics = MetricsCollector()
        self._setup_logger()
    
    def _setup_logger(self):
        """设置日志记录器"""
        # 清除现有的处理器
        self.logger.handlers.clear()
        
        # 如果config是dataclass对象，转换为字典
        if hasattr(self.config, '__dict__'):
            config_dict = self.config.__dict__
        else:
            config_dict = self.config
        
        # 设置日志级别
        level = getattr(logging, config_dict.get('level', 'INFO').upper())
        self.logger.setLevel(level)
        
        # 创建格式化器
        formatter = logging.Formatter(
            config_dict.get('format', '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        )
        
        # 控制台处理器
        if config_dict.get('enable_console', True):
            console_handler = logging.StreamHandler()
            console_handler.setFormatter(formatter)
            self.logger.addHandler(console_handler)
        
        # 文件处理器
        if config_dict.get('enable_file', False) and config_dict.get('file_path'):
            file_path = Path(config_dict['file_path'])
            file_path.parent.mkdir(parents=True, exist_ok=True)
            
            file_handler = logging.handlers.RotatingFileHandler(
                file_path,
                maxBytes=config_dict.get('max_file_size', 10 * 1024 * 1024),
                backupCount=config_dict.get('backup_count', 5),
                encoding='utf-8'
            )
            file_handler.setFormatter(formatter)
            self.logger.addHandler(file_handler)
    
    def log_with_metrics(self, level: str, message: str, extra: Dict[str, Any] = None):
        """记录日志并收集指标"""
        # 记录日志
        log_method = getattr(self.logger, level.lower())
        log_method(message, extra=extra or {})
        
        # 收集指标
        self.metrics.increment_counter('log_messages_total', tags={'level': level.upper()})
        
        if level.upper() in ['ERROR', 'CRITICAL']:
            self.metrics.increment_counter('error_messages_total')
    
    def debug(self, message: str, extra: Dict[str, Any] = None):
        self.log_with_metrics('debug', message, extra)
    
    def info(self, message: str, extra: Dict[str, Any] = None):
        self.log_with_metrics('info', message, extra)
    
    def warning(self, message: str, extra: Dict[str, Any] = None):
        self.log_with_metrics('warning', message, extra)
    
    def error(self, message: str, extra: Dict[str, Any] = None):
        self.log_with_metrics('error', message, extra)
    
    def critical(self, message: str, extra: Dict[str, Any] = None):
        self.log_with_metrics('critical', message, extra)

def timing_decorator(operation_name: str, logger: Optional[EnhancedLogger] = None):
    """计时装饰器"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            start_time = time.time()
            success = True
            error = None
            result = None
            
            try:
                result = func(*args, **kwargs)
                return result
            except Exception as e:
                success = False
                error = str(e)
                raise
            finally:
                duration = time.time() - start_time
                
                if logger:
                    # 记录操作日志
                    input_data = {'args': str(args)[:200], 'kwargs': str(kwargs)[:200]}
                    output_data = {'result': str(result)[:200] if result else None}
                    
                    logger.metrics.log_operation(
                        operation=operation_name,
                        input_data=input_data,
                        output_data=output_data,
                        duration=duration,
                        success=success,
                        error=error
                    )
                    
                    # 记录日志
                    if success:
                        logger.info(f"{operation_name} completed in {duration:.4f}s")
                    else:
                        logger.error(f"{operation_name} failed in {duration:.4f}s: {error}")
        
        return wrapper
    return decorator

def setup_logging(config: Dict[str, Any]) -> EnhancedLogger:
    """设置日志系统"""
    return EnhancedLogger('calculator_server', config)

def get_system_metrics() -> Dict[str, Any]:
    """获取系统指标"""
    import psutil
    import sys
    
    try:
        process = psutil.Process()
        
        return {
            'cpu_percent': process.cpu_percent(),
            'memory_info': {
                'rss': process.memory_info().rss,
                'vms': process.memory_info().vms,
                'percent': process.memory_percent()
            },
            'threads': process.num_threads(),
            'open_files': len(process.open_files()),
            'connections': len(process.connections()),
            'python_version': sys.version,
            'uptime': time.time() - process.create_time()
        }
    except ImportError:
        return {
            'error': 'psutil not available',
            'python_version': sys.version,
            'uptime': 'unknown'
        }